<?php

class GameboardModel extends Model
{
	public function GetGame( $gameID )
	{
		require_once 'obj/Game.php';
		require_once 'obj/User.php';
		require_once 'obj/Player.php';
		require_once 'obj/Robot.php';
		require_once 'obj/Map.php';
		require_once 'obj/TurnData.php';

		$game = null;
		$players = array();

		$stmt = $this->db->Prepare( "SELECT Users.UserID, Users.Username, Users.Email, GP.StillPlaying, GP.FinishedTurn, RobotData.PositionX, RobotData.PositionY, RobotData.RespawnPosX, RobotData.RespawnPosY, RobotData.Direction, RobotData.RobotTypeID, RobotData.HP, RobotData.Lives, RobotData.Alive, RobotData.LockedRegisterCards, RobotData.BonusCards, RobotData.RobotDataID, Cards.Cards, TD.TurnDataID, TD.Register1, TD.Register2, TD.Register3, TD.Register4, TD.Register5, TD.PowerDown, TD.SpawnLogic
											FROM GameParticipants AS GP
												INNER JOIN Users ON Users.UserID = GP.UserID
												INNER JOIN RobotData ON RobotData.GameID = GP.GameID AND RobotData.UserID = Users.UserID AND RobotData.RobotDataID = ( SELECT MAX( RobotDataID ) FROM RobotData WHERE GameID = GP.GameID AND UserID = Users.UserID )
												LEFT OUTER JOIN GameCardsDealed AS Cards ON Cards.GameID = GP.GameID AND Cards.UserID = Users.UserID AND Cards.Turn = ( SELECT MAX( Turn ) FROM Turns WHERE GameID = GP.GameID )
												LEFT OUTER JOIN TurnData AS TD ON TD.GameID = GP.GameID AND TD.Turn = ( SELECT MAX( Turn ) FROM Turns WHERE GameID = GP.GameID ) AND TD.UserID = Users.UserID
											WHERE GP.GameID = ?" );
		$stmt->bind_param( "i", $gameID );
		$stmt->execute();
		$stmt->bind_result( $row_userID, $row_username, $row_email, $row_stillPlaying, $row_finishedTurn, $row_posX, $row_posY, $row_respawnPosX, $row_respawnPosY, $row_direction, $row_robotTypeID, $row_hp, $row_lives, $row_alive, $row_lockedRegisterCards, $row_bonusCards, $row_robotDataID, $row_cards, $row_turnDataID, $row_register1, $row_register2, $row_register3, $row_register4, $row_register5, $row_powerDown, $row_spawnLogic );
		while ( $stmt->fetch() )
		{
			$players[] = new Player( new User( $row_userID, $row_username, $row_email ), new Robot( $row_robotDataID, $row_posX, $row_posY, $row_respawnPosX, $row_respawnPosY, $row_direction, $row_robotTypeID, $row_hp, $row_lives, $row_alive, $row_lockedRegisterCards, $row_bonusCards ), $row_cards, $row_stillPlaying, $row_finishedTurn, new TurnData( $row_turnDataID, $row_register1, $row_register2, $row_register3, $row_register4, $row_register5, $row_powerDown, $row_spawnLogic ) );
		}
		$stmt->close();

		$stmt = $this->db->Prepare( "SELECT Games.GameID, Users.UserID, Users.Username, Users.Email, Games.RandomSeed, Games.MaxPlayers, Games.Version, Games.GameModeID, Games.TurnResponseTimer, Games.TurnTimer, Games.Finished, Games.Password, Games.Started, Turns.Turn, Maps.MapID, Maps.Width, Maps.Height, Maps.Tiles, Maps.Name
										FROM Games
											INNER JOIN Users ON Users.UserID = Games.CreatorID
											INNER JOIN Turns ON Turns.GameID = Games.GameID AND Turns.Turn = ( SELECT MAX( Turn ) FROM Turns WHERE GameID = Games.GameID )
											INNER JOIN Maps ON Maps.MapID = Games.MapID
										WHERE Games.GameID = ?" );
		$stmt->bind_param( "i", $gameID );
		$stmt->execute();
		$stmt->bind_result( $row_gameID, $row_creatorID, $row_creatorName, $row_creatorEmail, $row_randomSeed, $row_maxPlayers, $row_version, $row_gameModeID, $row_turnResponseTimer, $row_turnTimer, $row_finished, $row_password, $row_started, $row_turn, $row_mapID, $row_mapWidth, $row_mapHeight, $row_mapTiles, $row_mapName );
		$stmt->fetch();
		$game = new Game( $row_gameID, new User( $row_creatorID, $row_creatorName, $row_creatorEmail ), $row_randomSeed, $row_maxPlayers, $row_version, $row_gameModeID, $row_turnResponseTimer, $row_turnTimer, $row_finished, $row_password, $row_started, $row_turn, new Map( $row_mapID, $row_mapWidth, $row_mapHeight, $row_mapTiles, $row_mapName ), $players );
		$stmt->close();
		
		return $game;
	}

	public function MakeMove( $game, $self, $registerCards )
	{
		if ( $game->Finished() )
		{
			throw new Exception( 'The game is already finished.' );
		}

		if ( $self->FinishedTurn() )
		{
			throw new Exception( 'You have already finished your turn.' );
		}

		if ( count( $registerCards) != 5 )
		{
			throw new Exception( 'Invalid amount of cards in register.' );
		}

		if ( count( array_unique( $registerCards ) ) != count( $registerCards ) )
		{
			throw new Exception( 'There are duplicates of cards in your registers.' );
		}

		for ( $i = 0; $i < count( $registerCards); $i++ )
		{
			if ( !in_array( $registerCards[$i], explode( ",", $self->Cards() ) ) )
			{
				throw new Exception( 'Invalid cards placed in register.' );
			}
		}

		$userID = $self->User()->ID();
		$powerDown = "false";
		$spawnLogic = "none";
		$gameID = $game->ID();
		$turn = $game->Turn();
		$userID = $self->User()->ID();
		$turnDataID = null;

		$this->db->StartTransaction();

		$stmt = $this->db->Prepare( "INSERT INTO TurnData ( GameID, Turn, Register1, Register2, Register3, Register4, Register5, PowerDown, SpawnLogic, UserID ) VALUES ( ?, ?, ?, ?, ?, ?, ?, ?, ?, ? )" );
		$stmt->bind_param( "iiiiiiissi", $gameID, $turn, $registerCards[0], $registerCards[1], $registerCards[2], $registerCards[3], $registerCards[4], $powerDown, $spawnLogic, $userID );
		$this->db->Execute( $stmt );
		$turnDataID = $this->db->LastInsertId();
		$stmt->close();

		$stmt = $this->db->Prepare( "UPDATE GameParticipants SET FinishedTurn = 1 WHERE GameID = ? AND UserID = ?" );
		$stmt->bind_param( "ii", $gameID, $userID );
		$this->db->Execute( $stmt );
		$stmt->close();

		if ( !$this->db->EndTransaction() )
		{
			throw new Exception( 'Could not store your move.' );
		}

		return true;
	}

	public function ReadyCheck( $game )
	{
		foreach ( $game->Players() as $player )
		{
			if ( !$player->FinishedTurn() )
			{
				return false;
			}
		}

		return true;
	}

	public function GetTurnData( $gameID, $turn, $userID )
	{
		require_once 'obj/TurnData.php';

		$turnData = null;

		$stmt = $this->db->Prepare( "SELECT TD.TurnDataID, TD.Register1, TD.Register2, TD.Register3, TD.Register4, TD.Register5, TD.PowerDown, TD.SpawnLogic
									FROM TurnData AS TD
									WHERE TD.GameID = ? AND TD.Turn = ? AND TD.UserID = ?" );
		$stmt->bind_param( "iii", $gameID, $turn, $userID );
		$stmt->execute();
		$stmt->bind_result( $row_turnDataID, $row_register1, $row_register2, $row_register3, $row_register4, $row_register5, $row_powerDown, $row_spawnLogic );
		$stmt->fetch();
		$turnData = new TurnData( $row_turnDataID, $row_register1, $row_register2, $row_register3, $row_register4, $row_register5, $row_powerDown, $row_spawnLogic );
		$stmt->close();

		if ( !$turnData )
		{
			throw new Exception( 'Could not fetch turn data.' );
		}

		return $turnData;
	}

	public function PrepareNextTurn( $game, $currentGame )
	{
		$this->db->StartTransaction();

		$gameID = $game->ID();
		$turn = $game->Turn();

		foreach ( $game->Players() as $player )
		{
			$cPlayer = null;
			for ( $i = 0; $i < count( $currentGame->m_players ); $i++ )
			{
				if ( $currentGame->m_players[$i]->m_name == $player->User()->Name() )
				{
					$cPlayer = $currentGame->m_players[$i];
					break;
				}
			}

			$userID = $player->User()->ID();
			$robotTypeID = $player->Robot()->RobotTypeID();

			$bonusCards = "";
			$lockedRegisterCards = "";

			for ( $i = 0; $i <= 4; $i++ )
			{
				if ( $cPlayer->m_robot->m_registers[$i] )
				{
					if ( $cPlayer->m_robot->m_registers[$i]->m_locked )
					{
						$lockedRegisterCards .= ( $cPlayer->m_robot->m_registers[$i]->m_card->m_priority * 0.1 ) - 1;
					}
				}

				if ( $i < 4 )
				{
					$lockedRegisterCards .= ",";
				}
			}

			// Uppdatera robotdata
			$stmt = $this->db->Prepare( "INSERT INTO RobotData ( GameID, UserID, RobotTypeID, PositionX, PositionY, HP, Lives, Alive, RespawnPosX, RespawnPosY, LockedRegisterCards, BonusCards, Direction )
														VALUES ( ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ? )" );
			$stmt->bind_param( "iiiiiiiiiissi", $gameID, $userID, $robotTypeID, $cPlayer->m_robot->m_posX, $cPlayer->m_robot->m_posY, $cPlayer->m_robot->m_health, $cPlayer->m_robot->m_lives, $cPlayer->m_robot->m_alive, $cPlayer->m_robot->m_spawnX, $cPlayer->m_robot->m_spawnY, $lockedRegisterCards, $bonusCards, $cPlayer->m_robot->m_direction );
			$this->db->Execute( $stmt );
			$stmt->close();

			// Sätt spelarnas FinishedTurn till false
			$stmt = $this->db->Prepare( "UPDATE GameParticipants SET FinishedTurn = 0 WHERE UserID = ?" );
			$stmt->bind_param( "i", $userID );
			$this->db->Execute( $stmt );
			$stmt->close();
		}

		// Sätt turn finished på turnen för gamet
		$stmt = $this->db->Prepare( "UPDATE Turns SET TurnFinished = 1 WHERE GameID = ? AND Turn = ?" );
		$stmt->bind_param( "ii", $gameID, $turn );
		$this->db->Execute( $stmt );
		$stmt->close();

		// Lägga in ny turn för gamet
		$newTurn = $turn + 1;
		$stmt = $this->db->Prepare( "INSERT INTO Turns ( Turn, GameID, Turns.Date, TurnFinished ) VALUES ( ?, ?, NOW(), 0 )" );
		$stmt->bind_param( "ii", $newTurn, $gameID );
		$this->db->Execute( $stmt );
		$stmt->close();

		if ( !$this->db->EndTransaction() )
		{
			throw new Exception( 'Could not store your move.' );
		}

		// Dela ut nya kort
		require_once 'php/lib/CardDealer.php';
		$dealer = new CardDealer( $this->GetGame( $gameID ) );
		$dealer->DealCards( $this->db );
	}
}
